package cn.donting.jme.edit.context.input;

import com.jme3.input.Input;
import com.jme3.input.KeyInput;
import com.jme3.input.RawInputListener;
import com.jme3.input.event.KeyInputEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * fx 键盘输入
 * TODO:映射不全
 * @see com.jme3.input.AWTKeyInput
 */
@Slf4j
public class FxKeyInput implements EventHandler<KeyEvent>, KeyInput {
    private Node fxNode;
    private RawInputListener listener;
    private boolean initialize = false;
    private final ArrayList<KeyInputEvent> eventQueue = new ArrayList<KeyInputEvent>();
    private static final HashMap<KeyCode, JmeCode> fxToJmeKeyCode = new HashMap<>();
    static {
        fxToJmeKeyCode.put(KeyCode.A, new JmeCode(KeyInput.KEY_A, 'A'));
        fxToJmeKeyCode.put(KeyCode.B, new JmeCode(KeyInput.KEY_B, 'B'));
        fxToJmeKeyCode.put(KeyCode.C, new JmeCode(KeyInput.KEY_C, 'C'));
        fxToJmeKeyCode.put(KeyCode.D, new JmeCode(KeyInput.KEY_D, 'D'));
        fxToJmeKeyCode.put(KeyCode.E, new JmeCode(KeyInput.KEY_E, 'E'));
        fxToJmeKeyCode.put(KeyCode.F, new JmeCode(KeyInput.KEY_F, 'F'));
        fxToJmeKeyCode.put(KeyCode.G, new JmeCode(KeyInput.KEY_G, 'G'));
        fxToJmeKeyCode.put(KeyCode.H, new JmeCode(KeyInput.KEY_H, 'H'));
        fxToJmeKeyCode.put(KeyCode.I, new JmeCode(KeyInput.KEY_I, 'I'));
        fxToJmeKeyCode.put(KeyCode.J, new JmeCode(KeyInput.KEY_J, 'J'));
        fxToJmeKeyCode.put(KeyCode.K, new JmeCode(KeyInput.KEY_K, 'K'));
        fxToJmeKeyCode.put(KeyCode.L, new JmeCode(KeyInput.KEY_L, 'L'));
        fxToJmeKeyCode.put(KeyCode.M, new JmeCode(KeyInput.KEY_M, 'M'));
        fxToJmeKeyCode.put(KeyCode.N, new JmeCode(KeyInput.KEY_N, 'N'));
        fxToJmeKeyCode.put(KeyCode.O, new JmeCode(KeyInput.KEY_O, 'O'));
        fxToJmeKeyCode.put(KeyCode.P, new JmeCode(KeyInput.KEY_P, 'P'));
        fxToJmeKeyCode.put(KeyCode.Q, new JmeCode(KeyInput.KEY_Q, 'Q'));
        fxToJmeKeyCode.put(KeyCode.R, new JmeCode(KeyInput.KEY_R, 'R'));
        fxToJmeKeyCode.put(KeyCode.S, new JmeCode(KeyInput.KEY_S, 'S'));
        fxToJmeKeyCode.put(KeyCode.T, new JmeCode(KeyInput.KEY_T, 'T'));
        fxToJmeKeyCode.put(KeyCode.U, new JmeCode(KeyInput.KEY_U, 'U'));
        fxToJmeKeyCode.put(KeyCode.V, new JmeCode(KeyInput.KEY_V, 'V'));
        fxToJmeKeyCode.put(KeyCode.W, new JmeCode(KeyInput.KEY_W, 'W'));
        fxToJmeKeyCode.put(KeyCode.X, new JmeCode(KeyInput.KEY_X, 'X'));
        fxToJmeKeyCode.put(KeyCode.Y, new JmeCode(KeyInput.KEY_Y, 'Y'));
        fxToJmeKeyCode.put(KeyCode.Z, new JmeCode(KeyInput.KEY_Z, 'Z'));
        fxToJmeKeyCode.put(KeyCode.SPACE, new JmeCode(KeyInput.KEY_SPACE, '0'));
        fxToJmeKeyCode.put(KeyCode.ESCAPE, new JmeCode(KeyInput.KEY_ESCAPE, '0'));
        fxToJmeKeyCode.put(KeyCode.TAB, new JmeCode(KeyInput.KEY_TAB, '0'));
        fxToJmeKeyCode.put(KeyCode.CAPS, new JmeCode(KeyInput.KEY_CAPITAL, '0'));
        fxToJmeKeyCode.put(KeyCode.DELETE, new JmeCode(KeyInput.KEY_DELETE, '0'));
        fxToJmeKeyCode.put(KeyCode.DELETE, new JmeCode(KeyInput.KEY_DELETE, '0'));

    }

    @Override
    public void initialize() {
        initialize = true;
    }

    public void bind(Node node) {
        node.addEventHandler(KeyEvent.KEY_PRESSED, this);
        node.addEventHandler(KeyEvent.KEY_RELEASED, this);
        fxNode = node;
    }

    @Override
    public void update() {
        synchronized (eventQueue) {
            // flush events to listener
            for (int i = 0; i < eventQueue.size(); i++) {
                listener.onKeyEvent(eventQueue.get(i));
            }
            eventQueue.clear();
        }
    }

    @Override
    public void destroy() {
        fxNode.removeEventHandler(KeyEvent.KEY_PRESSED, this);
        fxNode.removeEventHandler(KeyEvent.KEY_RELEASED, this);
        fxNode = null;
        initialize = false;
    }

    @Override
    public boolean isInitialized() {
        return initialize;
    }

    @Override
    public void setInputListener(RawInputListener listener) {
        this.listener = listener;
    }

    @Override
    public long getInputTimeNanos() {
        return System.nanoTime();
    }


    @Override
    public void handle(KeyEvent event) {
        log.debug(event.toString());
        KeyCode code = event.getCode();
        JmeCode jmeCode = fxToJmeKeyCode.get(code);
        if (jmeCode == null) {
            return;
        }
        KeyInputEvent keyInputEvent;
        if (event.getEventType().equals(KeyEvent.KEY_PRESSED)) {
            keyInputEvent = new KeyInputEvent(jmeCode.code, jmeCode.chart, true, false);
        } else {
            keyInputEvent = new KeyInputEvent(jmeCode.code, jmeCode.chart, false, false);
        }
        synchronized (eventQueue) {
            // flush events to listener
            eventQueue.add(keyInputEvent);
        }
    }

//    @Override
    public String getKeyName(int key) {
        return null;
    }


    private static class JmeCode {
        public final int code;
        public final char chart;

        public JmeCode(int code, char chart) {
            this.code = code;
            this.chart = chart;
        }
    }

    public static void main(String[] args) {
        String s = "fxToJmeKeyCode.put(KeyCode.0,new JmeCode(KeyInput.KEY_0,'0'));";

        for (int i = 'A'; i <= 'Z'; i++) {
            System.out.println(s.replaceAll("0", (char) i + ""));
        }

    }
}
